/*
 * Contains lobby screen code
 */

#include <string.h>
#include <stdbool.h>
#include <allegro.h>
#include "main.h"
#include "network.h"
#include "world/player.h"
#include "main.h"
#include "util/log.h"
#include "game.h"
#include "draw/chat.h"
#include "draw/colors.h"

#define INQUIRY_INTERVAL (FPS/3)
#define HUGE_INQUIRY_INTERVAL (FPS*5)
#define MAX_SERVERNAME_LEN 100

CtoSmessage netmessage; // For communications to server
StoCmessage received;  // For communications to server
int inquiry_countdown; // Ticks until next attempt to send pending requests to server
int ready; // indicates this client ready status
bool setready; // If true, automatically go ready after connect

// Lobby configuration
static char servername [MAX_SERVERNAME_LEN]; // server address
static char nickname [MAX_NAMELEN]; // my nickname
	
/* send a friendly hello msg to server */
void send_hello ()
{
	netmessage.type = CtoS_HELLO;
	strcpy (netmessage.nickname, nickname);
	send_CtoSmessage (&netmessage);
}

/* send player registration request. TODO: REDESIGN in later versions */
void send_player ()
{
	netmessage.type = CtoS_LOBBY_ADDPLAYER;
	strcpy (netmessage.data.nickname, nickname);
	netmessage.data.character_type = 2;
	send_CtoSmessage (&netmessage);
}

static void send_ready (bool ready)
{
	netmessage.type = ready ? CtoS_LOBBY_READY : CtoS_LOBBY_NOTREADY;
	send_CtoSmessage (&netmessage);
}

static void send_chat(const char* text) {
	CtoSmessage msg;
	msg.type = CtoS_CHAT;
	strcpy (msg.line, text);
	send_CtoSmessage(&msg);
}

void lobby_configure (const char* server, const char* name, bool autoready)
{
	strncpy (servername, server, MAX_SERVERNAME_LEN-1);
	strncpy (nickname, name, MAX_NAMELEN-1);
	servername[MAX_SERVERNAME_LEN-1] = '\0';
	servername[MAX_NAMELEN-1] = '\0';
	setready = autoready;
}

void lobby_init ()
{
	show_mouse (screen);
	
	network_init (servername);
	send_hello ();
	send_player ();
	if (setready) send_ready (1);

	chat_init ();
	
	inquiry_countdown = HUGE_INQUIRY_INTERVAL;
	ready = 0;
}

void lobby_cleanup ()
{
	show_mouse (NULL);
}

// true if client has been registered on server
int server_has_my_client ()
{
	for (int i = 0; i < MAX_CLIENTS; i++) if (the_network.client[i].uid == my_uid) return 1;
	return 0;
}

static int my_player ()
{
	for (int i = 0; i < MAX_PLAYERS; i++) 
		if ((*the_network.player[i].nickname != 0) && (the_network.client[the_network.owner[i]].uid == my_uid)) return i;
	return -1;
}

// true if player has been registered on server [NEEDS REDESIGN in later versions]
int server_has_my_player ()
{
	return my_player() != -1;
}

void lobby_update ()
{
	inquiry_countdown --;
	
	if (inquiry_countdown <= 0) {
		inquiry_countdown = INQUIRY_INTERVAL;
		// fire bits of request to server
		if (!server_has_my_client()) send_hello (); else
		if (!server_has_my_player()) send_player (); else
		if (setready && !the_network.client[my_player()].ready) send_ready (1); else {
			setready = 0; // Autoready only once
			inquiry_countdown = HUGE_INQUIRY_INTERVAL; // server has all data, wait longer
		}
	}
	
	receive_StoCmessage (&received);
	while (received.type != StoC_NOMSG) {
		switch (received.type) {
		
		case StoC_LOBBY_CLIENTREADY:
			the_network.client[received.clientidx].ready = 1;
			break;
		
		case StoC_LOBBY_CLIENTNOTREADY:
			the_network.client[received.clientidx].ready = 0;
			break;
		
		case StoC_LOBBY_SEEDGAME:
			the_network.player[my_player()].character_type =
				((unsigned) received.seed) % 9; // DEBUG: randomize player char
			log_debug ("[Lobby] Seed game with %lu for %d characters.",
			           received.seed, received.n_characters);
			game_seed (received.seed, received.n_characters);
			break;
		
		case StoC_LOBBY_STARTGAME:
			game_my_player = my_player (); // set var in game.h
			log_debug ("[Lobby] I control player %d.", game_my_player);
			change_state (STATE_GAME); // players are ready, go in-game
			return; // get out of here to be safe from gamestate-consistency errors
		
		case StoC_CHAT:
			chat_receive (received.line);
			break;
		
		default:
			log_fatal ("Received unidentified message type %d from server.",
			           received.type);
			break;
			
		}
		
		receive_StoCmessage (&received);
	} 
	
	if (keypressed ()) {
		char* line;
		if ((line = chat_input ()) != NULL) {
			send_chat (line);
			if (strncmp (line, "ready", 5) == 0) {
				ready = !ready;
				send_ready (ready);
			}
		}		
	}
}

void lobby_draw ()
{
	int i;
	
	acquire_bitmap (buffer);
	clear_bitmap (buffer);
	
	// border
	rectfill (buffer, 5, 5, DISPLAY_WIDTH-25, DISPLAY_HEIGHT-5, LOBBY_COL);
	rectfill (buffer, 15, 15, DISPLAY_WIDTH-15, DISPLAY_HEIGHT-15, 0);
	
	// clients border
	rectfill (buffer, 20, 30, DISPLAY_WIDTH/2-10, DISPLAY_HEIGHT-20, LOBBY_COL);
	rectfill (buffer, 25, 35, DISPLAY_WIDTH/2-15, DISPLAY_HEIGHT-25, 0);
	
	// players border
	rectfill (buffer, DISPLAY_WIDTH/2+10, 30, DISPLAY_WIDTH-20, DISPLAY_HEIGHT-20, LOBBY_COL);
	rectfill (buffer, DISPLAY_WIDTH/2+15, 35, DISPLAY_WIDTH-25, DISPLAY_HEIGHT-25, 0);
	
	textout_centre_ex (buffer, font, "Lobby", DISPLAY_WIDTH/2, 20, LOBBY_COL_BRIGHT, 0);
	textout_centre_ex (buffer, font, "Clients", DISPLAY_WIDTH/4, 40, LOBBY_COL_BRIGHT, 0);
	textout_centre_ex (buffer, font, "Players", DISPLAY_WIDTH*3/4, 40, LOBBY_COL_BRIGHT, 0);
	
	for (i = 0; i < MAX_CLIENTS; i++) {
		if (*the_network.client[i].nickname == 0) break;
		textprintf_ex (buffer, font, 30, 50 + i * 25, LOBBY_COL_BRIGHT, 0, "%d: %s", i, the_network.client[i].nickname);
		if (the_network.client[i].ready)
			rectfill (buffer, DISPLAY_WIDTH/2-35, 50 + i * 25, DISPLAY_WIDTH/2-25, 60 + i * 25, LOBBY_COL_BRIGHT);
		else
			rect (buffer, DISPLAY_WIDTH/2-35, 50 + i * 25, DISPLAY_WIDTH/2-25, 60 + i * 25, LOBBY_COL_BRIGHT);
	}

	for (i = 0; i < MAX_PLAYERS; i++) {
		if (*the_network.player[i].nickname == 0) break;
		textprintf_ex (buffer, font, DISPLAY_WIDTH/2+30, 50 + i * 25, LOBBY_COL_BRIGHT, 0, "%s (%s)", the_network.player[i].nickname, the_network.client[the_network.owner[i]].nickname);
	}

	chat_display_messages ();
	chat_display_input ();
	
	release_bitmap (buffer);
}

